/*
 * Copyright (c) 2000-2017 wanglei. All rights reserved.
 * TeamDev PROPRIETARY and CONFIDENTIAL.
 * Use is subject to license terms.
 */

package com.xhb.ui;


import static javax.swing.SwingUtilities.invokeLater;

import java.awt.FileDialog;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

import org.noear.solon.Solon;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.teamdev.jxbrowser.browser.Browser;
import com.teamdev.jxbrowser.browser.SavePageType;
import com.teamdev.jxbrowser.browser.callback.CreatePopupCallback;
import com.teamdev.jxbrowser.browser.callback.CreatePopupCallback.Response;
import com.teamdev.jxbrowser.browser.callback.OpenPopupCallback;
import com.teamdev.jxbrowser.browser.callback.ShowContextMenuCallback;
import com.teamdev.jxbrowser.browser.callback.StartDownloadCallback;
import com.teamdev.jxbrowser.cookie.Cookie;
import com.teamdev.jxbrowser.cookie.CookieStore;
import com.teamdev.jxbrowser.frame.EditorCommand;
import com.teamdev.jxbrowser.js.JsObject;
import com.teamdev.jxbrowser.navigation.event.FrameLoadFinished;
import com.teamdev.jxbrowser.navigation.event.LoadProgressChanged;
import com.teamdev.jxbrowser.net.HttpHeader;
import com.teamdev.jxbrowser.net.callback.BeforeStartTransactionCallback;
import com.teamdev.jxbrowser.ui.Point;
import com.teamdev.jxbrowser.view.swing.BrowserView;
import com.xhb.EasyBrowserApplication;
import com.xhb.biz.service.ConfigService;
import com.xhb.ui.download.EasyStartDownloadCallback;
import com.xhb.ui.tools.Tools;

import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.http.HttpUtil;

/**
 * tab工厂
 *
 * @author wanglei.
 */
public final class TabFactory {

    private static final String BLANK = "about:blank";


    public static Tab createTab(Browser browser) {
        return createTab("about:blank", browser);
    }

	public static Tab createTab( String url, Browser browser) {

		// 强制当前页面跳转
		browser.set(CreatePopupCallback.class, params -> {
			browser.navigation().loadUrl(params.targetUrl());
			return Response.suppress();
		});
		
		final String newURl=url;

		browser.engine().network().set(BeforeStartTransactionCallback.class, params -> {
			List<HttpHeader> headers = new ArrayList<HttpHeader>();

			for (HttpHeader httpHeader : params.httpHeaders()) {
				if (!"User-Agent".toUpperCase().equalsIgnoreCase(httpHeader.name())
						&& !"Referer".toUpperCase().equalsIgnoreCase(httpHeader.name()))
					headers.add(httpHeader);
			}

			if (newURl.contains("static-mp-0a2340ef-6139-43d4-bd3c-b74789381b05")) {
				headers.add(HttpHeader.of("User-Agent",
						"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x6309071d)XWEB/8461"));
				headers.add(
						HttpHeader.of("Referer", "https://servicewechat.com/wx36867c1fc872509f/41/page-frame.html"));
			} else {
				headers.add(HttpHeader.of("User-Agent",
						"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x6309071d)XWEB/8461"));
				headers.add(HttpHeader.of("Referer", "https://servicewechat.com/wx87b93bb649b23f37/9/page-frame.html"));
			}

			return com.teamdev.jxbrowser.net.callback.BeforeStartTransactionCallback.Response.override(headers);
		});

		browser.navigation().on(FrameLoadFinished.class, event -> {
			browser.mainFrame().ifPresent(frame -> {
				JsObject jsObject = frame.executeJavaScript("window");
				if (jsObject != null) {
					jsObject.putProperty("java", new Tools());
					jsObject.putProperty("zyk", new Tools());
				}
			});
		});

		browser.navigation().on(LoadProgressChanged.class, event -> {
			browser.mainFrame().ifPresent(frame -> {
				JsObject jsObject = frame.executeJavaScript("window");
				if (jsObject != null) {
					jsObject.putProperty("java", new Tools());
					jsObject.putProperty("zyk", new Tools());
				}
			});
		});

		browser.mainFrame().ifPresent(mainFrame -> {
			JsObject jsObject = mainFrame.executeJavaScript("window");
			if (jsObject != null) {
				jsObject.putProperty("java", new Tools());
				jsObject.putProperty("zyk", new Tools());
			}
		});

		// 如果是自己的服务地址 在后面拼上 token
		url = Solon.context().getBean(ConfigService.class).getUserIndexUrl(url);
		BrowserView browserView = BrowserView.newInstance(browser);

		TabContent tabContent = new TabContent(browserView);
		final TabCaption tabCaption = new TabCaption();
		tabCaption.setTitle("about:blank");
		tabContent.addPropertyChangeListener("PageTitleChanged", new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent evt) {
				tabCaption.setTitle((String) evt.getNewValue());
			}
		});
		browser.set(OpenPopupCallback.class, new DefaultOpenPopupCallback());
		browser.set(ShowContextMenuCallback.class, new ContextMenu(browserView));
		browser.set(StartDownloadCallback.class, new EasyStartDownloadCallback());

		Cookie cookie = Solon.context().getBean(ConfigService.class).getCookie();
		if (null != cookie) {
			// 浏览器用户登陆后就给标签页添加 cookie 以访问服务端页面
			CookieStore cookieStore = browserView.getBrowser().profile().cookieStore();
			cookieStore.set(cookie);
			cookieStore.persist();
		}
		if (!StringUtils.isBlank(url)) {
			browser.navigation().loadUrl(url);
			tabContent.getToolBar().setUrl(url);
		}

		EasyBrowserApplication.getShortcutHandle().regBrowserShortcutKeys(browser);
		return new Tab(tabCaption, tabContent);
	}
}

/**
 * 浏览器使用新页签打开新窗口
 */
class DefaultOpenPopupCallback implements OpenPopupCallback {


    @Override
    public Response on(Params params) {
        Browser browser = params.popupBrowser();
        invokeLater(() -> {
            /*BrowserView view = BrowserView.newInstance(browser);*/
            EasyBrowserApplication.insertTab(TabFactory.createTab(browser.url(), browser));
        });
        return Response.proceed();
    }
}

class ContextMenu implements ShowContextMenuCallback {

    private static LinkedHashMap<String, EditorCommand> executeCommandMap = new LinkedHashMap();

    static {
        executeCommandMap.put("复制", EditorCommand.copy());
        executeCommandMap.put("剪切", EditorCommand.cut());
        executeCommandMap.put("全选", EditorCommand.selectAll());
        executeCommandMap.put("取消全选", EditorCommand.unselect());
    }


    private BrowserView browserView;

    private String preImgSrc;

    ContextMenu(BrowserView browserView) {
        this.browserView = browserView;
    }

    @Override
    public void on(Params params, Action action) {
        preImgSrc = null;
        if (!StringUtils.isBlank(params.srcUrl())) {
            preImgSrc = params.srcUrl();
        }
        ContextMenu contextMenu = this;
        SwingUtilities.invokeLater(() -> {
            JPopupMenu popupMenu = new JPopupMenu();
            popupMenu.addPopupMenuListener(new PopupMenuListener() {
                @Override
                public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                }

                @Override
                public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                    if (!action.isClosed()) {
                        action.close();
                    }
                }

                @Override
                public void popupMenuCanceled(PopupMenuEvent e) {
                }
            });
            //复制剪切等
            for (String key : executeCommandMap.keySet()) {
                JMenuItem commandMenu = new JMenuItem(key);
                commandMenu.setEnabled(browserView.getBrowser().mainFrame().get().isCommandEnabled(executeCommandMap.get(key).name()));
                //处理点击事件
                commandMenu.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        browserView.getBrowser().mainFrame().get().execute(executeCommandMap.get(key));
                    }
                });
                popupMenu.add(commandMenu);
            }
            popupMenu.addSeparator();

            //图片相关操作
            if (preImgSrc != null) {
                initImgMenu(popupMenu);
            }

            //前进后退刷新
            JMenuItem reload = new JMenuItem("重新加载(F5)");
            reload.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    browserView.getBrowser().navigation().reload();
                }
            });
            popupMenu.add(reload);
            //前进后退刷新
            JMenuItem back = new JMenuItem("后退");
            back.setEnabled(browserView.getBrowser().navigation().canGoBack());
            back.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    browserView.getBrowser().navigation().goBack();
                }
            });
            popupMenu.add(back);
            JMenuItem forward = new JMenuItem("前进");
            forward.setEnabled(browserView.getBrowser().navigation().canGoForward());
            forward.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    browserView.getBrowser().navigation().goForward();
                }
            });
            popupMenu.add(forward);
            popupMenu.addSeparator();

            //打印
            JMenuItem print = new JMenuItem("打印");
            print.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    browserView.getBrowser().mainFrame().get().print();
                }
            });
            popupMenu.add(print);
            popupMenu.addSeparator();
            JMenuItem saveAs = new JMenuItem("另存为");
            saveAs.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    JFileChooser fileChooser = new JFileChooser();
                    fileChooser.setSelectedFile(new File("index.html"));
                    int result = fileChooser.showSaveDialog(browserView);
                    if (result == JFileChooser.APPROVE_OPTION) {
                        File selectedFile = fileChooser.getSelectedFile();
                        browserView.getBrowser().saveWebPage(Paths.get(selectedFile.getAbsolutePath()),
                                Paths.get(selectedFile.getParent()), SavePageType.COMPLETE_HTML);
                    }
                }
            });
            popupMenu.add(saveAs);
//            JMenuItem devTools = new JMenuItem("开发者工具(F12)");
//            devTools.addActionListener(new ActionListener() {
//                public void actionPerformed(ActionEvent e) {
//                    browserView.getBrowser().devTools();
//                }
//            });
//            popupMenu.add(devTools);
            //查看源代码
            JMenuItem viewCode = new JMenuItem("查看源代码");
            viewCode.addActionListener(new ToolBar.ViewCode(browserView));
            popupMenu.add(viewCode);
            JMenuItem clearCache = new JMenuItem("清理缓存");
            clearCache.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    browserView.getBrowser().profile().httpCache().clear().join();
                    browserView.getBrowser().profile().cookieStore().deleteAll();
                    browserView.getBrowser().profile().cookieStore().persist();
                }
            });
            popupMenu.add(clearCache);
            // Display context menu at specified location.
            Point location = params.location();
            popupMenu.show(browserView, location.x(), location.y());

        });
    }

    /**
     * 图片右键的一些菜单
     *
     * @param popupMenu
     */
    public void initImgMenu(JPopupMenu popupMenu) {
        //前进后退刷新
        JMenuItem copyImg = new JMenuItem("复制图片");
        copyImg.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    //如果此处报错 Invalid argument to native writeImage 请尝试使用Oracle-JDK 不要使用 OPEN JDK
                    byte[] bytes = HttpUtil.downloadBytes(preImgSrc);
                    BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(bytes));
                    setImageClipboard(bufferedImage);
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        });
        JMenuItem saveImg = new JMenuItem("图片另存为...");
        saveImg.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    URL url = new URL(preImgSrc);
                    FileDialog saveDialog = new FileDialog(EasyBrowserApplication.getFrame(), "选择位置", FileDialog.SAVE);
                    String fileName = FileNameUtil.getName(url.getPath());
                    if (fileName == null || preImgSrc.equals(fileName)) {
                        fileName = "img.jpg";
                    }
                    saveDialog.setFile(fileName);
                    saveDialog.setVisible(true);
                    if (!StringUtils.isBlank(saveDialog.getDirectory())) {
                        HttpUtil.downloadFile(preImgSrc, saveDialog.getDirectory() + saveDialog.getFile());
                    }
                } catch (MalformedURLException ex) {
                    throw new RuntimeException(ex);
                }

            }
        });
//        JMenuItem newTabOpen = new JMenuItem("在新标签页中打开图片");
//        newTabOpen.addActionListener(new ActionListener() {
//            @Override
//            public void actionPerformed(ActionEvent e) {
//                EasyBrowserApplication.insertTab(TabFactory.createTab(preImgSrc,
//                        EasyBrowserApplication.getEngine().newBrowser()));
//            }
//        });
        JMenuItem copyUrl = new JMenuItem("复制图片链接");
        copyUrl.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                // 封装文本内容
                Transferable trans = new StringSelection(preImgSrc);
                // 把文本内容设置到系统剪贴板
                clipboard.setContents(trans, null);
            }
        });

        popupMenu.add(saveImg);
        popupMenu.add(copyImg);
//        popupMenu.add(newTabOpen);
        popupMenu.add(copyUrl);
    }

    /**
     * 写入图片到剪切板
     *
     * @param image
     */
    public static void setImageClipboard(BufferedImage image) {
        ImageSelection imgSel = new ImageSelection(image);
        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(imgSel, null);
    }

    public static class ImageSelection implements Transferable {
        private BufferedImage image;

        public ImageSelection(BufferedImage image) {
            this.image = image;
        }

        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[]{DataFlavor.imageFlavor};
        }

        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return DataFlavor.imageFlavor.equals(flavor);
        }

        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            if (!DataFlavor.imageFlavor.equals(flavor)) {
                throw new UnsupportedFlavorException(flavor);
            }
            return image;
        }
    }

}